package com.bigknow.appstore.server.cert;

import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

public final class CAManager {

	private static final char[] KEYSTORE_PASS = "atlas".toCharArray();

	private static CAManager caManager = new CAManager();

	private static final X500Name CA_ISSUER = new X500Name(
			"C=CN,ST=北京,L=北京,O=北京卓微天成科技咨询有限公司,OU=北京卓微天成科技咨询有限公司,CN=北京卓微天成科技咨询有限公司,E=zhaonaiy@bigknow.com.cn");

	private CAManager() {
		Security.addProvider(new BouncyCastleProvider());
	}

	public static CAManager getInstance() {
		return caManager;
	}

	public void generateKeyStore(String dn, String id, OutputStream out) throws NoSuchAlgorithmException,
			KeyStoreException, UnrecoverableKeyException, CertificateException, OperatorCreationException, IOException,
			InvalidKeyException, NoSuchProviderException, SignatureException {
		try {
			KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
			kpg.initialize(2048);
			KeyPair keyPair = kpg.generateKeyPair();
			KeyStore caStore = KeyStore.getInstance("JKS");
			caStore.load(CAManager.class.getResourceAsStream("ca.jks"), KEYSTORE_PASS);
			X509Certificate caCert = (X509Certificate) caStore.getCertificate("bigknow");
			String subject = dn + ", dn=" + id;
			Certificate cert = generateV3(subject, BigInteger.ZERO, new Date(System.currentTimeMillis() - 1000 * 60
					* 60 * 24), new Date(System.currentTimeMillis() + 1000L * 60 * 60 * 24 * 365 * 32),
					keyPair.getPublic(), (PrivateKey) caStore.getKey("bigknow", KEYSTORE_PASS));
			KeyStore store = KeyStore.getInstance("JKS");
			store.load(null, null);
			store.setKeyEntry("privateKey", keyPair.getPrivate(), KEYSTORE_PASS, new Certificate[] { cert, caCert });
			store.setCertificateEntry("ca", caCert);
			store.store(out, KEYSTORE_PASS);
		} finally {
			out.close();
		}
	}

	private Certificate generateV3(String subject, BigInteger serial, Date notBefore, Date notAfter,
			PublicKey publicKey, PrivateKey privKey) throws CertificateException, IOException,
			OperatorCreationException {
		X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(CA_ISSUER, serial, notBefore, notAfter,
				new X500Name(subject), publicKey);
		ContentSigner sigGen = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(privKey);
		X509CertificateHolder holder = builder.build(sigGen);
		CertificateFactory cf = CertificateFactory.getInstance("X.509");
		try (InputStream is1 = new ByteArrayInputStream(holder.toASN1Structure().getEncoded())) {
			return cf.generateCertificate(is1);
		}
	}

	public static void main(String[] args) throws UnrecoverableKeyException, InvalidKeyException,
			NoSuchAlgorithmException, KeyStoreException, CertificateException, OperatorCreationException,
			NoSuchProviderException, SignatureException, FileNotFoundException, IOException {
		CAManager.getInstance().generateKeyStore("C=CN,ST=zw,L=zw,O=商务局,OU=商务局,CN=商务局,E=@bigknow.com.cn", "zw",
				new FileOutputStream("time.jks"));
	}
}
